Binding classes
This chapter introduces the classes that Python scripts can use in Birdee. We use Python type hint syntax to show the members of the classes.
Error classes
class CompileError:
linenumber: int #readonly, the line number of the error
pos: int #readonly, the position of characters in the line
msg: str #readwrite, the error message
The compile error that was actually raised. It can be got from function get_compile_error
.
class TokenizerError:
linenumber: int #readonly, the line number of the error
pos: int #readonly, the position of characters in the line
msg: str #readwrite, the error message
The compile error that was actually raised. It can be got from function get_tokenizer_error
.
Containers and Ownership pointers
Ownership pointer
class SOMEUniquePtr:
def get() -> SOME
The ownership pointer of the AST class SOME
. SOME
above can be replaced by some AST node classes, which can be StatementAST
, etc. This UniquePtr class represents the ownership of an AST node. If the ownership is not transfered to another AST node, the AST node will be destroyed when Python runtime reclaim the memory of this ownership pointer object. A reference to AST node is a pointer that has no ownership of the node. You can use get()
on a ownership pointer to get the reference of the AST node. You cannot get fields or call member functions directly on ownership pointers. Instead, you can operate on a reference by calling get()
. For more information, please refer to the "Compile time scripts" chapter of Birdee language manual.
For most of the sub-classes of StatementAST and ExprAST, if you get a field of them with type StatementAST
, you will get a reference. If you assign a value to the StatementAST
typed fields, you usually need a StatementASTUniquePtr
and the field will take over the ownership.
List
class SOMEList:
def pop_back(): ... # remove the last item
def push_back(itm: SOMEUniquePtr): ... # append an item to the list, will take the owner ship of the itm
def __getitem__(idx: int): ...
def __setitem__(idx: int, itm: SOMEUniquePtr): ... #will take the ownership of the itm
def __len__() -> int: ...
def __iter__(): ...
A list of AST nodes. SOME
above can be replaced by some AST node classes, which can be MemberFunctionDef
, FieldDef
, etc. You can use the list as a normal Python list. The [...]
and for ... in ...
are allowed on AST node lists.
AST classes
BasicType
class BasicType(Enum):
CLASS
NULL
FUNC
VOID
BYTE
SHORT
INT
LONG
ULONG
UINT
FLOAT
DOUBLE
BOOLEAN
POINTER
PACKAGE
It is an enum which represents the basic types.
ResolvedType
class ResolvedType:
base: BasicType # readonly, the base type of the resolved type
index_level: int # readwrite, is it an array? 0 for not array, 1 for 1D array and so on
def is_class() -> bool: ... # if it is a class (not struct)
def is_integer() -> bool: ... # if it is an integer
def get_detail() -> ???: ... # get the detailed info of the type. See comments below.
def set_detail(_base: BasicType, detail): ... # set the basic type and details
def __init__():...
def __str__() -> str: ... # convert the type into a string
def __eq__(other: ResolvedType) -> bool: ... # if another type is equal to this
The internal class that represents a resolved type. It basically contains three parts.
* base
is the base type of the type. If it is a basic type (e.g. int), this field should be a enum value (e.g. BasicType.INT
). If the type is a class/struct, this field should be BasicType.CLASS
. The detailed ClassAST of the referenced class can be found by detail
. If the base type is a BasicType.FUNC
, the type is a functype or closure.
* index_level
is the dimension of the array. If it is 0, the type is not an array. If it is larger than 0, the type is a index_level
-D array of type specified by base
.
* detail
is the detailed information of the type. If the type is a class/struct type, get_detail()
will return a reference to ClassAST of the referenced class. If the type is a functype or closure, get_detail()
will return a reference to PrototypeAST.
SourcePos
class SourcePos:
source_idx: int #readwrite, a unique index for the source file name
line: int #readwrite, the line number
pos: int #readwrite, the position of characters in the line
This class represents a position in the source code. Most of the AST nodes contains a SourcePos object to mark the position of the AST in the source file.
PrototypeAST
class PrototypeAST:
prefix: str # readonly. returns the symbol prefix of the Function definition.
# For example, if the function is defined in a module "com.a", the prefix should be "com.a."
name: str # readwrite. the function name or function type name
return_type: ResolvedType # readwrite. The return type of the function
args: VariableSingleDefASTList # readonly. The argument definitions
is_closure: bool # readwrite. if the function is a closure
cls: ClassAST # readwrite. The class where the function is defined. Can be None if is not a member function
This class holds the information of a function type (functype or closure). It also holds information of a function definition.
Template Parameters and Arguments
Birdee's function and class templates can have placeholders for types and constant values. The placeholders which are declared in the template definition is called "template parameters" in Birdee compiler. For example, the class
class Templ[T1,T2, v as int]
end
has three template parameters, namely T1, T2 and v. The first two are type paramters and the last is constant value parameter. In Python binding, you can access the parameters via the TemplateParameter
, TemplateParameters_ClassAST
and TemplateParameters_FunctionAST
.
The class TemplateParameter
represents one single template parameter. TemplateParameters_ClassAST
and TemplateParameters_FunctionAST
are the template parameter lists for classes and functions
class TemplateParameter:
type: BasicType # readonly. It is CLASS if the template parameter is a type parameter
# Otherwise, it is a constant value parameter with the type
name: str # readwrite. The name of the parameter
class TemplateParameters_ClassAST: #TemplateParameters_FunctionAST is the same
params: TemplateParameterList # readonly
source: str # readonly. The source code of the template
On the other hand, the template arguments are the acutal types/values that are given to the templates when using an instance of template.
class TemplateArgument:
class TemplateArgumentType(Enum):
TEMPLATE_ARG_TYPE
TEMPLATE_ARG_EXPR
kind: TemplateArgumentType # readwrite, the kind of the argument, type? value?
resolved_type: ResolvedType # readwrite. The resolved type for the type argument or the value
expr: StatementAST # readwrite. The value expression of the argument. Writing to it needs an ownership pointer and will take the ownership of it
AST base classes
class StatementAST:
pos: SourcePos # readwrite
def run(func): ... # run a function "func" on the sub AST nodes of this node
def copy(func) -> StatementASTUniquePtr: ... # copy this AST node
class ExprAST(StatementAST):
resolved_type: ResolvedType #readwrite, the type of the expression
def is_lvalue() -> bool: ... # returns true if the expression is an LValue (has an address)
These two classes are super classes for most of the AST nodes.
FunctionAST
This class represents a function definition (with body), or a function declaration (without body).
class FunctionAST(ExprAST):
body: StatementASTList # readonly, the list of statement AST of the body of the function
proto: PrototypeAST # readonly, the prototype of the function
capture_on_stack: bool # readwrite, if the captured variables of the function is stored on stack
is_declare: bool # readwrite, if the function is a declaration or imported from other module
is_template_instance: bool # readwrite, if the function is an instance of template function
is_imported: bool # readwrite, if the function is imported from other modules
template_instance_args: TemplateArgumentList # readonly, if is an template instance, the template argument list; Otherwise None
template_source_func: FunctionAST # readonly, if is an template instance, the source template function; Otherwise None
capture_this: bool # readwrite, if the function captures "this"
is_template: bool # readonly, if the function is a template function
parent: FunctionAST # readonly, if is an closure function, the function that contains the current function; Otherwise None
link_name: str # readwrite, the link-time name for the function.
# Specifiled by the "alias" clause of function definition
template_param: TemplateParameters_FunctionAST # readonly, if is a template function, the template parameters; Otherwise, None
AnnotationStatementAST
An annotated statement is wrapped in an AnnotationStatementAST. For example, Birdee code
@some
function f()
end
has an AnnotationStatementAST which contains a FunctionAST.
class AnnotationStatementAST(StatementAST):
@static
def new(annotations: list, impl: StatementASTUniquePtr): ...
#static function, create a new AnnotationStatementAST node. "annotations" is a list of string that are for annotations
#"impl" is the annotated AST node. Will take the ownership of "impl"
is_expr: bool # readwrite, if this annotated statement is an expression
anno: list # readwrite, a list of annotations in string
impl: StatementASTUniquePtr # the ownership pointer of the annotated AST. Reading this field will yield a reference
ScriptAST
The AST for the embeded scripts, i.e., between {@ @}
.
class ScriptAST(ExprAST):
@static
def new(script: str, is_top_level:bool):... # creates a new ScriptAST. "is_top_level" specifies whether is script is in the top level.
stmt: StatementASTList # readonly, the generated statement AST by the script
script: str # readwrite, the script
ResolvedIdentifierExprAST
class ResolvedIdentifierExprAST(ExprAST):
def is_mutable()-> bool : ... # is this value mutable?
This class is an abstract class, which represents an simple primary expression (function name or variable), or a number literal, etc.
StringLiteralAST
class StringLiteralAST(ResolvedIdentifierExprAST):
@static
def new(value: str): ... # create a new StringLiteralAST
value: str # the string value of the literal
This class of AST represents string literals, usually surrounded by a pair of "
, like "Hello"
in Birdee code.
NumberExprAST
The AST for number literals. e.g. 1.23
.
class NumberExprAST(ResolvedIdentifierExprAST):
@static
def new(type: BasicType, value): ... # creates a new number with given type
value: ??? # readwrite, the value of the number literal
type: BasicType # readwrite, the type of the number literal
def __str__()->str : ... # convert the value to a Python string
ArrayInitializerExprAST
class ArrayInitializerExprAST(ExprAST):
@static
def new(impl: list): ... # create an array from a list of StatementASTUniquePtr
values: ExprASTList # readonly, the list of expressions in the array
This class of AST represents array literals, like [1,2,3,4]
.
ReturnAST
class ReturnAST(StatementAST):
@static
def new(retv: StatementASTUniquePtr): ... # create a return statement from an expression. Takes the ownership
expr: StatementASTUniquePtr # readwrite, the expression that is returned. Can be None if returns void.
This class of AST represents the return statements, like return 0
.
IdentifierExprAST
class IdentifierExprAST(ExprAST):
@static
def new(variable_name: str):... #create a new identifier expression. The variable name of the expression is given by the parameter
name: str # readwrite, the variable name
impl: StatementASTUniquePtr # readwrite, the resolved expression AST. The values of this field
# should be a subclass of ResolvedIdentifierExprAST
This class represents an identifier expression. For example,
a = b
here a
and b
are two IdentifierExprASTs. If b
is resolved as an variable, the impl
field will be a LocalVarExprAST. If b
is an function name, the impl
field will be a ResolvedFuncExprAST.
ResolvedFuncExprAST
class ResolvedFuncExprAST(ResolvedIdentifierExprAST):
funcdef: FunctionAST # readwrite, the referenced function
This AST is used in IdentifierExprAST to represent a function.
ThisExprAST
class ThisExprAST(ExprAST):
@static
def new():... #create a new this expression
BoolLiteralExprAST
class BoolLiteralExprAST(ExprAST):
@static
def new(value: bool):... # create a new boolean literal expression
value: bool # readwrite, the value of the boolean literal
The AST for boolean literal, e.g. true
IfBlockAST
class IfBlockAST(StatementAST):
cond: ExprAST # readonly, the expression to be tested in an "if"
if_true: StatementASTList # readonly, the list of statements for the "true" condition of the "if" statement
if_falue: StatementASTList # readonly, the list of statements for the "else" block
ForBlockAST
class ForBlockAST(StatementAST):
is_dim: bool # readwrite, if the for loop's loop variable is defined in the for-statement
init_value: StatementASTUniquePtr # readwrite, if is_dim, the variable definition (VariableSingleDefAST).
# Otherwise, the initial value of the for loop varaiable
loop_var: ExprAST # readwrite, if is_dim==false, the variable definition of the loop variable. Otherwise, None
till: StatementASTUniquePtr # readwrite, the expression that marks the end of the loop-variable
inclusive: bool # readwrite, if true, it is a "for ... to ...". Otherwise, it is a "for ... till ..."
block: StatementASTList # readwrite, the for loop body
There are two kinds of for-loops in Birdee. One have the loop varaible defined in the "for" statement. The other does not have.
for dim i=0 to 3
...
end
for j=0 to 3
...
end
The difference of these two kinds of for-loop is reflected in the is_dim
field of the AST.
WhileBlockAST
class WhileBlockAST(StatementAST):
cond: StatementASTUniquePtr # readwrite, the contition expression of the while loop
block: StatementASTList # readonly, the body of the while loop
LoopControlAST
class LoopControlType(Enum):
BREAK
CONTINUE
class LoopControlAST(StatementAST):
@static
def new(type: LoopControlType):... # create a new "break" or "continue" statement
type: LoopControlType # readwrite, the kind of the loop control
This AST is either "break" or "continue"
BinaryExprAST
The expressions that applies an operator on two expressions.
class BinaryOp(Enum):
BIN_MUL # *
BIN_DIV # /
BIN_MOD # %
BIN_ADD # +
BIN_MINUS # -
BIN_LT # <
BIN_GT # >
BIN_LE # <=
BIN_GE # >=
BIN_EQ # ==
BIN_NE # !=
BIN_CMP_EQ # ===
BIN_CMP_NE # !==
BIN_AND # &
BIN_XOR # ^
BIN_OR # |
BIN_LOGIC_AND # &&
BIN_LOGIC_OR # ||
BIN_ASSIGN # =
class BinaryExprAST(ExprAST):
@static
def new(op: BinaryOp, lhs: StatementASTUniquePtr, rhs: StatementASTUniquePtr): ...
#create a new binary expression: lhs op rhs
is_overloaded: bool # readwrite, if this binary expression is an overloaded function call to a function
lhs: StatementASTUniquePtr # readwrite, the left hand side expression
rhs: StatementASTUniquePtr # readwrite, the right hand side expression
op: BinaryOp # readwrite the operation on the expressions
UnaryExprAST
The expressions that applies an operator on one expression.
class UnaryOp(Enum):
UNA_NOT # !
UNA_ADDRESSOF # addressof
UNA_POINTEROF # pointerof
UNA_TYPEOF # typeof
class UnaryExprAST(ExprAST):
is_overloaded: bool # readwrite, if the expression is an overloaded function call
# Otherise, None
arg: StatementASTUniquePtr # the expression that the operator applies to
op: UnaryOp # the operator
FunctionTemplateInstanceExprAST
The function template instance expression. For example in the code:
add[int,long](1,2)
The expression add[int,long]
is a function template instance.
class FunctionTemplateInstanceExprAST(ExprAST):
expr: UniquePtrStatementAST # readwrite, the function template
instance: FunctionAST # readwrite, the function template instance
IndexExprAST
The index expression or function template instance expression with only one template parameter.
class IndexExprAST(ExprAST):
expr: UniquePtrStatementAST # readwrite, the indexed expression (before [...])
index: UniquePtrStatementAST # readwrite, the index (within [...])
template_inst: UniquePtrStatementAST # readwrite, if is a template, the template instance expression.
# otherwise, None
def is_template_instance()->bool: ... # returns if it is a function template instance
CallExprAST
The AST for function calls.
class CallExprAST(ExprAST):
callee: UniquePtrStatementAST # readwrite, the callee expression (before (...) )
args: StatementASTList # readonly, arguments (within (...) )
VariableSingleDefAST
The AST which defines a single variable. Corresponds to dim
statements.
class VariableSingleDefAST(StatementAST):
# the types of captures of a variable
class CaptureType(Enum):
CAPTURE_NONE # not captured
CAPTURE_REF # capturing reference to the parent capture object
CAPTURE_VAL # capturing the values to the parent capture object
name: str # readwrite, the name of the variable
value: StatementASTUniquePtr # readwrite, the initial value of the variable. Can be None
resolved_type: ResolvedType # readwrite, the type of the variable
capture_import_type: CaptureType # readwrite, how the captured variable is imported from parent function
capture_import_idx: int # readwrite, the capture index within the parent function
capture_export_type: CaptureType # readwrite, how the captured variable is exported to child functions
capture_export_idx: int # readwrite, the capture index within capture object for the child functions
VariableMultiDefAST
The AST that contains multiple variable definitions.
class VariableMultiDefAST(StatementAST):
lst: VariableSingleDefASTList # readonly, the variable list
LocalVarExprAST
The AST used by IdentifierExprAST to reference variables.
class LocalVarExprAST(ResolvedIdentifierExprAST):
@static
def new(v: VariableSingleDefAST):... # creates a new LocalVarExprAST
vardef: VariableSingleDefAST # readwrite, the variable definition
FunctionToClosureAST
The AST automatically generated by compiler to convert a function to a closure.
class FunctionToClosureAST(ExprAST):
func: StatementASTUniquePtr # readwrite, the function/functype expression to be converted
TryBlockAST
The AST for "try ... catch ..." block. A try block may contain several catch variables to catch different types of exception. There are also the same number of "catch" blocks in the AST.
class TryBlockAST(StatementAST):
try_block: StatementASTList # readonly, try block
catch_variables: VariableSingleDefASTList # readonly, the definitions of the catch variables
def get_catch_block(idx: int) -> StatementASTList : ...
# get a catch block. The index is from 0 to len(catch_variables) - 1
ThrowAST
class ThrowAST(StatementAST):
expr: StatementASTUniquePtr # readwrite, the throw expression
Class ASTs
class AccessModifier(Enum):
PUBLIC
PRIVATE
class FieldDef:
@static
def new(index: int, access: AccessModifier, vdef: StatementASTUniquePtr) -> FieldDefUniquePtr: ...
# creates a new field, with given index, modifier and the variable definition (given by vdef)
index: int # readwrite, the index of the field within the class
access: AccessModifier # readwrite, the access modifier
decl: StatementASTUniquePtr # readwrite, should be VarialeSingleDefAST. The variable definition
class MemberFunctionDef:
@static
def new(access: AccessModifier, fdef: StatementASTUniquePtr) -> MemberFunctionDef: ...
# creates a new field, with modifier and the FunctionAST (given by fdef)
access: AccessModifier # readwrite, the access modifier
decl: StatementASTUniquePtr # readwrite, should be FunctionAST. The function definition
class ClassAST(StatementAST):
name: str # readwrite, the name of the class
fields: FieldDefList # readonly, the list of fields
funcs: MemberFunctionDefList # readonly, the list of member functions
template_instance_args: TemplateArgumentList # readonly, the list of the template arguement if it is a template instance
template_source_class: ClassAST # readonly, the template source AST if it is a template instance
template_param: TemplateParameters_ClassAST # readonly, the template parameters if it is a template
needs_rtti: bool # readwrite, if the class has RTTI enabled
is_struct: bool # readonly, if it is a struct instead of a class
parent_class: ClassAST # readonly, the parent class that this class inherits from
def is_template_instance() -> bool: ... # returns if it is a template instance
def is_template() -> bool: ... # returns if it is a template
def get_unique_name()-> str: ... # returns the fully qualified name of the class
def find_field(name: str) -> (int,FieldDef): ... # find a field by name from this class.
# returns a tuple (int, FieldDef). The int is the number of levels of parents where the field is found.
# the returned FieldDef may not be in the current class
NewExprAST
The AST for new
AST, including newing an array or an object.
class NewExprAST(ExprAST):
args: StatementASTList # readonly, the list of arguments/dimensions to the new expression
func: FunctionAST # readwrite, the constructor function to be called
MemberExprAST
The AST for referencing members of an object, or functions/variables imported from other modules.
class MemberExprAST(ResolvedIdentifierExprAST):
class MemberType(Enum):
ERROR
PACKAGE # if it is an package. e.g. in "mod1.mod2.v1", "mod1.mod2" is of type "PACKAGE"
FIELD # a field of an object
FUNCTION # a member function of an object
IMPORTED_DIM # an imported variable of other modules
VIRTUAL_FUNCTION # a virtual function of an object, will read the vtable to generate the callee
IMPORTED_FUNCTION # a function of an imported module
@static
def new(obj: StatementASTUniquePtr, name: str): ... # creates a new member expr "obj.name"
@static
def new_func_member(obj: StatementASTUniquePtr, member: MemberFunctionDef): ... # creates a new member function expr
kind: MemberType # the kind of the member
obj: StatementASTUniquePtr # the object
# the following fields can only be read when this class actually stores that kind of value
# you can get the kind of the exact value by "kind" field
func: MemberFunctionDef
field: FieldDef
imported_func: FunctionAST
import_dim: VariableSingleDefAST
def to_string_array()->list: ... # convert the member expr chain to a list of python string
Number Cast AST
This is a class of AST classes. Each converts a number type from another. The FROM and TO in the code below are two number types.
class CastNumberExpr_FROM_TO(ExprAST):
@static
def new(expr: StatementASTUniquePtr):... # creates a new Number Cast AST
expr: StatementASTUniquePtr # the expression to be converted